
import UIKit
import CommonCrypto


class FFullAESSpeed: NSObject {

    /// key：32
    static func encrypt(plaintext: String, key: String) -> String {
        
        guard let dataToEncrypt = plaintext.data(using: .utf8) else {
            return ""
        }
        
        var keyData = key.data(using: .utf8)!
        if keyData.count < kCCKeySizeAES256 {
            keyData.append(Data(repeating: 0, count: kCCKeySizeAES256 - keyData.count))
        } else if keyData.count > kCCKeySizeAES256 {
            keyData = keyData.subdata(in: 0..<kCCKeySizeAES256)
        }
        
        let cryptLength = dataToEncrypt.count + kCCBlockSizeAES128
        var cryptData = Data(count: cryptLength)
        
        
        let keyLength = size_t(kCCKeySizeAES256)
        let options = CCOptions(kCCOptionPKCS7Padding)
        
        var numBytesEncrypted: size_t = 0
        let cryptStatus = cryptData.withUnsafeMutableBytes { cryptBytes in
            dataToEncrypt.withUnsafeBytes { dataBytes in
                keyData.withUnsafeBytes { keyBytes in
                    CCCrypt(CCOperation(kCCEncrypt),
                            CCAlgorithm(kCCAlgorithmAES),
                            options,
                            keyBytes.baseAddress,
                            keyLength,
                            nil,
                            dataBytes.baseAddress,
                            dataToEncrypt.count,
                            cryptBytes.baseAddress,
                            cryptLength,
                            &numBytesEncrypted)
                }
            }
        }
        
        
        guard cryptStatus == kCCSuccess else {
            return ""
        }
        
        cryptData.removeSubrange(numBytesEncrypted..<cryptData.count)
        return cryptData.base64EncodedString()
    }
    
    static func decrypt(ciphertext: String, key: String) -> String {
        
        guard let dataToDecrypt = Data(base64Encoded: ciphertext) else {
            return ""
        }
        
        var keyData = key.data(using: .utf8)!
        if keyData.count < kCCKeySizeAES256 {
            keyData.append(Data(repeating: 0, count: kCCKeySizeAES256 - keyData.count))
        } else if keyData.count > kCCKeySizeAES256 {
            keyData = keyData.subdata(in: 0..<kCCKeySizeAES256)
        }
        
        
        let cryptLength = dataToDecrypt.count
        var cryptData = Data(count: cryptLength)
        
        
        let keyLength = size_t(kCCKeySizeAES256)
        let options = CCOptions(kCCOptionPKCS7Padding)
        
        var numBytesDecrypted: size_t = 0
        let cryptStatus = cryptData.withUnsafeMutableBytes { cryptBytes in
            dataToDecrypt.withUnsafeBytes { dataBytes in
                keyData.withUnsafeBytes { keyBytes in
                    CCCrypt(CCOperation(kCCDecrypt),
                            CCAlgorithm(kCCAlgorithmAES),
                            options,
                            keyBytes.baseAddress,
                            keyLength,
                            nil,
                            dataBytes.baseAddress,
                            dataToDecrypt.count,
                            cryptBytes.baseAddress,
                            cryptLength,
                            &numBytesDecrypted)
                }
            }
        }
        
        
        guard cryptStatus == kCCSuccess else {
            return ""
        }
        
        
        cryptData.removeSubrange(numBytesDecrypted..<cryptData.count)
        guard let decryptedString = String(data: cryptData, encoding: .utf8) else {
            return ""
        }
        
        return decryptedString
    }
}
